"""
>>> valid_field_names1 = ['age', 'gender', 'year']
>>> parser1 = QueryFilterParser(valid_field_names1)

######################
# Valid query_filter #
######################

>>> print parser1(None)
(AND: )

>>> print parser1("")
(AND: )

>>> print parser1("age>=20")
(AND: ('age__gte', 20L))

>>> print parser1("age>=20 and age <= 27")
(AND: ('age__gte', 20L), ('age__lte', 27L))

>>> print parser1("(age>=20 and age <= 27)")
(AND: ('age__gte', 20L), ('age__lte', 27L))

>>> print parser1("(age>=20 and age <= 27) and gender='M'")
(AND: ('age__gte', 20L), ('age__lte', 27L), ('gender__exact', 'M'))

>>> print parser1("(age>=20 and age <= 27) OR (year>2 and year<5)")
(OR: (AND: ('age__gte', 20L), ('age__lte', 27L)), (AND: ('year__gt', 2L), ('year__lt', 5L)))

>>> print parser1("(age>=20 and age <= 27) OR (year>2 and year<5) and gender='M'")
(AND: (OR: (AND: ('age__gte', 20L), ('age__lte', 27L)), (AND: ('year__gt', 2L), ('year__lt', 5L))), (AND: ('gender__exact', 'M')))

>>> print parser1("((age>=20 or year>2) and (age<=27 or year<5) or age>=20) and gender='M'")
(AND: (OR: (AND: (OR: ('age__gte', 20L), ('year__gt', 2L)), (OR: ('age__lte', 27L), ('year__lt', 5L))), (AND: ('age__gte', 20L))), (AND: ('gender__exact', 'M')))

########################
# Invalid query_filter #
########################

>>> print parser1(" ") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected a valid field name (age, gender, year) (at char 1), (line:1, col:2)

>>> print parser1("age") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected a valid lookup type (<, <=, =, >=, >) (at char 3), (line:1, col:4)

>>> print parser1("age>=") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected W:(0123...) (at char 5), (line:1, col:6)

>>> print parser1("age> = 20") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected W:(0123...) (at char 5), (line:1, col:6)

>>> print parser1("age> = 20") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected W:(0123...) (at char 5), (line:1, col:6)

>>> print parser1("age>=20 and") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected end of text (at char 8), (line:1, col:9)

>>> print parser1("(age>=20 and age <= 27 and gender='M'") # doctest:+ELLIPSIS
Traceback (most recent call last):
...
ParseException: Expected ")" (at char 37), (line:1, col:38)

###########
# Caching #
###########

# Same parser instance with same query_filter
>>> query_filter1 = "age>18 and gender='F'"
>>> q1 = parser1(query_filter1)
>>> q2 = parser1(query_filter1)
>>> id(q1) == id(q2)
True

# Same parser instance with different query_filter
>>> query_filter2 = "age>18"
>>> q3 = parser1(query_filter2)
>>> id(q1) == id(q3)
False

# Different parser instances with same valid_field_names and same query_filter
>>> parser2 = QueryFilterParser(valid_field_names1)
>>> q4 = parser2(query_filter1)
>>> id(q1) == id(q4)
True

# Different parser instances with same valid_field_names and different query_filter
>>> q5 = parser2(query_filter2)
>>> id(q1) == id(q5)
False

# Different parser instances with different valid_field_names and same query_filter
>>> valid_field_names2 = ['age', 'gender']
>>> parser3 = QueryFilterParser(valid_field_names2)
>>> q6 = parser3(query_filter1)
>>> id(q1) == id(q6)
False

# Different parser instances with different valid_field_names and different query_filter
>>> q7 = parser3(query_filter2)
>>> id(q1) == id(q7)
False
"""

from parser import QueryFilterParser

if __name__ == '__main__':
    import doctest
    doctest.testmod()
